package com.demo.token;

import org.apache.commons.codec.binary.Base64;

import java.lang.reflect.Method;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by john on 15/1/8.
 */
public class RSAUtil {

    private static String publicKey;
    private static String privateKey;

    private static String qfbaoPublicKey;
    private static String qfbaoPrivateKey;

    static {
        try {
            Map<String, Object> keyMap = RSACoder.getKeyMap();
            publicKey = RSACoder.getPublicKey(keyMap);
            privateKey = RSACoder.getPrivateKey(keyMap);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 私钥解密
     *
     * @param data base64加密数据
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKeyBASE64(String data)
            throws Exception {
        byte[] encryptedData = RSACoder.getBASE64Decoder().decode(data);
        byte[] bytes = RSACoder.decryptByPrivateKey(encryptedData, privateKey);
        return new String(bytes);
    }

    /**
     * 公钥解密
     *
     * @param data base64加密数据
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKeyBASE64(String data) throws Exception {
        byte[] encryptedData = RSACoder.getBASE64Decoder().decode(data);
        byte[] bytes = RSACoder.decryptByPublicKey(encryptedData, publicKey);
        return new String(bytes);
    }

    /**
     * 私钥加密
     *
     * @param data 源数据
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKeyBASE64(byte[] data)
            throws Exception {
        byte[] encryptedData = RSACoder.encryptByPrivateKey(data, privateKey);
        Base64 base64 = new Base64();
        return base64.encodeToString(encryptedData);
        //return RSACoder.getBASE64Encoder().encode(encryptedData);
    }

    /**
     * 巧房宝私钥加密
     *
     * @param data 源数据
     * @return
     * @throws Exception
     */
    public static String encryptByQfbaoPrivateKeyBASE64(byte[] data)
            throws Exception {
        byte[] encryptedData = RSACoder.encryptByPrivateKey(data, qfbaoPrivateKey);
        return RSACoder.getBASE64Encoder().encodeToString(encryptedData);
    }
    /**
     * 巧房宝公钥解密
     *
     * @param data base64加密数据
     * @return
     * @throws Exception
     */
    public static String decryptByQfbaoPublicKeyBASE64(String data,String publicKey) throws Exception {
        byte[] encryptedData = RSACoder.getBASE64Decoder().decode(data);
        byte[] bytes = RSACoder.decryptByPublicKey(encryptedData, publicKey);
        return new String(bytes);
    }
    /**
     * 公钥加密
     *
     * @param data      源数据
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKeyBASE64(byte[] data)
            throws Exception {
        byte[] encryptedData = RSACoder.encryptByPublicKey(data, publicKey);
        return RSACoder.getBASE64Encoder().encodeToString(encryptedData);
    }

    /**
     * 私钥转换成C#格式
     * @param encodedPrivateKey
     * @return
     */
    public static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivateKey) {
        try {
            StringBuffer buff = new StringBuffer(1024);

            PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
                    encodedPrivateKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
                    .generatePrivate(pvkKeySpec);

            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + encodeBase64(removeMSZero(pvkKey.getModulus()
                    .toByteArray())) + "</Modulus>");

            buff.append("<Exponent>"
                    + encodeBase64(removeMSZero(pvkKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");

            buff.append("<P>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeP()
                    .toByteArray())) + "</P>");

            buff.append("<Q>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeQ()
                    .toByteArray())) + "</Q>");

            buff.append("<DP>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeExponentP()
                    .toByteArray())) + "</DP>");

            buff.append("<DQ>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeExponentQ()
                    .toByteArray())) + "</DQ>");

            buff.append("<InverseQ>"
                    + encodeBase64(removeMSZero(pvkKey.getCrtCoefficient()
                    .toByteArray())) + "</InverseQ>");

            buff.append("<D>"
                    + encodeBase64(removeMSZero(pvkKey.getPrivateExponent()
                    .toByteArray())) + "</D>");
            buff.append("</RSAKeyValue>");

            return buff.toString();
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }
    /**
     * base64编码
     * @param input
     * @return
     * @throws Exception
     */
    public static String encodeBase64(byte[] input) throws Exception {
        Class clazz = Class
                .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod = clazz.getMethod("encode", byte[].class);
        mainMethod.setAccessible(true);
        Object retObj = mainMethod.invoke(null, new Object[] { input });
        return (String) retObj;
    }
    /**
     * @param data
     * @return
     */
    private static byte[] removeMSZero(byte[] data) {
        byte[] data1;
        int len = data.length;
        if (data[0] == 0) {
            data1 = new byte[data.length - 1];
            System.arraycopy(data, 1, data1, 0, len - 1);
        } else
            data1 = data;

        return data1;
    }

    public static void main(String[] args){
        Map<String,Object> token = new HashMap<>();
        token.put("employeeUuid","324343");
        token.put("companyUuid","33");
//        try {
//            encryptByPrivateKeyBASE64();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }


}
